package net.mingsoft.report_data.biz.impl.report_gen;

import com.alibaba.fastjson.JSON;
import net.mingsoft.report_data.biz.ZkDataOnVacationFlowPopulationBiz;
import net.mingsoft.report_data.dao.ZkDataDao;
import net.mingsoft.report_data.entity.ZkDataInIslandFlowPopulationPerDayEntity;
import net.mingsoft.report_data.entity.vo.DateWithCountDto;
import net.mingsoft.report_data.entity.vo.UserPeakDto;
import net.mingsoft.report_data.enums.ReportPeriodType;
import net.mingsoft.report_data.util.AreaUtil;
import net.mingsoft.report_data.util.MathUtil;
import net.mingsoft.report_data.util.PeriodUtil;
import net.mingsoft.report_data.util.ReportFtlRender;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.helpers.MessageFormatter;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 节假日人口流动分析报告
 *
 * @author gengfa
 * @date 22/05/26
 */
@Service(value = "ON_VACATION_FLOW_POPULATION")
public class ZkDataOnVacationFlowPopulationBizImpl implements ZkDataOnVacationFlowPopulationBiz {

    @Resource
    ZkDataDao dataDao;

    @Resource
    FreeMarkerConfigurer configurer;

    private static final String DESC_TOURIST_TREND = "据统计，本周全省旅游用户累计{}人";
    private static final String DESC_TOURIST_TREND_P2 = "其中{}的累计旅游用户共{}人，占全省旅游用户{}%，其次是{}，累计旅游用户共{}人，占全省旅游用户{}%。";

    @Override
    public String generate(ReportPeriodType periodType) {
        Map<String, Object> map = PeriodUtil.getDateArgs(periodType);
        getUserPeak(map);
        getOutProvinceFlowUserTrend(map);
        getAbroadFlowUserTrend(map);
        getTouristTrend(map);
        getOutProvinceUserMigrateTrend(map);
        getAbroadUserMigrateTrend(map);
        return ReportFtlRender.render(configurer, "report/form-jjrrkdtfx.ftl", map);
    }

    @Override
    public Map<String, Object> getUserPeak(Map<String, Object> map) {
        // 获取时间区间数据
        final String beginDate = (String) map.get("beginDate");
        final String endDate = (String) map.get("endDate");
        List<ZkDataInIslandFlowPopulationPerDayEntity> entities = dataDao.selectTouristArea(beginDate, endDate);

        entities = entities.stream().filter(o -> StringUtils.isNotBlank(o.getFromArea())&&!o.getFromArea().trim().equals("未知")).collect(Collectors.toList());
        // 初始化参数
        List<UserPeakDto> userPeakDtoList = new ArrayList<>();

        // 分组求出区域人口峰值
        Map<String, List<ZkDataInIslandFlowPopulationPerDayEntity>> entitiesMap
                = entities.stream().collect(
                        Collectors.groupingBy(ZkDataInIslandFlowPopulationPerDayEntity::getFromArea));
        for (Map.Entry<String, List<ZkDataInIslandFlowPopulationPerDayEntity>> listEntry :
                entitiesMap.entrySet()) {
            if (listEntry.getValue() != null && listEntry.getValue().size() > 0) {
                ZkDataInIslandFlowPopulationPerDayEntity maxE = listEntry.getValue()
                        .stream().max((o1, o2) -> o1.getCount() > o2.getCount() ? 1 : -1).get();
                userPeakDtoList.add(new UserPeakDto()
                        .setDate(maxE.getDay())
                        .setCity(maxE.getFromArea())
                        .setCounty(maxE.getFromArea())
                        .setCount(maxE.getCount()));
            }
        }
        userPeakDtoList.sort(Comparator.comparing(UserPeakDto::getCount).reversed());
        userPeakDtoList = userPeakDtoList.stream().filter(o -> !AreaUtil.belongsHaiKouArea(o.getCounty())).collect(Collectors.toList());
        map.put("userPeakDtoList", JSON.toJSONString(userPeakDtoList));
        return map;
    }

    @Override
    public Map<String, Object> getOutProvinceFlowUserTrend(Map<String, Object> map) {
        // 获取时间区间数据
        final String beginDate = (String) map.get("beginDate");
        final String endDate = (String) map.get("endDate");
        List<DateWithCountDto> outProvinceFlowUserList =
                dataDao.selectOutProvinceFlowUser(beginDate, endDate);
        map.put("outProvinceFlowUserList", JSON.toJSONString(outProvinceFlowUserList));
        return map;
    }

    @Override
    public Map<String, Object> getAbroadFlowUserTrend(Map<String, Object> map) {
        // 获取时间区间数据
        final String beginDate = (String) map.get("beginDate");
        final String endDate = (String) map.get("endDate");
        List<DateWithCountDto> abroadFlowUserList =
                dataDao.selectAbroadFlowUser(beginDate, endDate);
        map.put("AbroadFlowUserList", JSON.toJSONString(abroadFlowUserList));
        return map;
    }

    @Override
    public Map<String, Object> getTouristTrend(Map<String, Object> map) {
        // 获取时间区间数据
        final String beginDate = (String) map.get("beginDate");
        final String endDate = (String) map.get("endDate");
        List<ZkDataInIslandFlowPopulationPerDayEntity> entities = dataDao.selectTouristArea(beginDate, endDate);

        int totalTourist = entities.stream().mapToInt(ZkDataInIslandFlowPopulationPerDayEntity::getCount).sum();

        entities = entities.stream().filter(o -> StringUtils.isNotBlank(o.getFromArea())&&!o.getFromArea().trim().equals("未知")).collect(Collectors.toList());

        Map<String, List<DateWithCountDto>> mergeDtoMap = entities.stream().collect(Collectors.groupingBy(ZkDataInIslandFlowPopulationPerDayEntity::getFromArea)).entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, o -> {
            List<DateWithCountDto> dtos = new ArrayList<>();
            o.getValue().forEach(e -> {
                dtos.add(new DateWithCountDto().setDate(e.getDay()).setCount(String.valueOf(e.getCount())));
            });
            return dtos;
        }));

        for (Map.Entry<String, List<DateWithCountDto>> entry : mergeDtoMap.entrySet()) {
            entry.getValue().sort(Comparator.comparing(DateWithCountDto::getDate));
        }

        // 拼接描述文本
        String basicDesc = MessageFormatter.format(DESC_TOURIST_TREND, totalTourist).getMessage();
        if (mergeDtoMap.entrySet().size() >= 2) {
            List<DateWithCountDto> areaTouristRank = mergeDtoMap.entrySet().stream().map(o -> new DateWithCountDto().setDatasource(o.getKey()).setCount(String.valueOf(o.getValue().stream().mapToInt(vo -> Integer.parseInt(vo.getCount())).sum()))).collect(Collectors.toList()).stream().sorted(Comparator.comparing(o -> Integer.parseInt(o.getCount()))).collect(Collectors.toList());
            DateWithCountDto dto0 = areaTouristRank.get(areaTouristRank.size()-1);
            DateWithCountDto dto1 = areaTouristRank.get(areaTouristRank.size()-2);
            map.put("descTouristTrend", basicDesc + "," + MessageFormatter.arrayFormat(DESC_TOURIST_TREND_P2, new String[]{dto0.getDatasource(),dto0.getCount(), MathUtil.getRate(Long.parseLong(dto0.getCount()), (long) totalTourist),dto1.getDatasource(),dto1.getCount(), MathUtil.getRate(Long.parseLong(dto1.getCount()), (long) totalTourist)}).getMessage());
        } else {
            map.put("descTouristTrend", basicDesc);
        }


        map.put("touristDtoList", JSON.toJSONString(mergeDtoMap));
        return map;
    }

    @Override
    public Map<String, Object> getOutProvinceUserMigrateTrend(Map<String, Object> map) {
        // 获取时间区间数据
        final String beginDate = (String) map.get("beginDate");
        final String endDate = (String) map.get("endDate");
        List<DateWithCountDto> outIslandFlowInUser =
                dataDao.countOutIslandFlowUser(beginDate, endDate, 0);
        List<DateWithCountDto> outIslandFlowOutUser =
                dataDao.countOutIslandFlowUser(beginDate, endDate, 1);
        map.put("outIslandFlowInUser", JSON.toJSONString(outIslandFlowInUser));
        map.put("outIslandFlowOutUser", JSON.toJSONString(outIslandFlowOutUser));
        return map;
    }

    @Override
    public Map<String, Object> getAbroadUserMigrateTrend(Map<String, Object> map) {
        // 获取时间区间数据
        final String beginDate = (String) map.get("beginDate");
        final String endDate = (String) map.get("endDate");
        List<DateWithCountDto> abroadFlowInUser =
                dataDao.countAbroadFlowUser(beginDate, endDate, 0);
        List<DateWithCountDto> abroadFlowOutUser =
                dataDao.countAbroadFlowUser(beginDate, endDate, 1);
        map.put("abroadFlowInUser", JSON.toJSONString(abroadFlowInUser));
        map.put("abroadFlowOutUser", JSON.toJSONString(abroadFlowOutUser));
        return map;
    }
}
